package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.lfasr.util.StringUtil;
import com.xbongbong.paas.pojo.AliyunRsaResponsePojo;
import com.xbongbong.paas.pojo.AliyunRsaWordPojo;
import com.xbongbong.paas.pojo.RecordContentPojo;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.service.AudioFileService;
import com.xbongbong.paas.service.AudioTranslatorService;
import com.xbongbong.paas.service.aliyun.AliyunHttpResponse;
import com.xbongbong.paas.service.aliyun.AliyunHttpUtil;
import com.xbongbong.paas.service.aliyun.AliyunRequestBody;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.constant.callcenter.CallCenterConstant;
import com.xbongbong.saas.domain.entity.CallCenterCallLogEntity;
import com.xbongbong.saas.model.CallCenterCallLogModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 阿里云语音转写服务类
 *
 * @author 章华隽
 * @mail nefeed@163.com
 * @time 2018-01-25 19:10
 */
@Service("aliyunAudioTranslatorService")
public class AliyunAudioTranslatorServiceImpl implements AudioTranslatorService {

    private static final Logger LOG = LoggerFactory.getLogger(AliyunAudioTranslatorServiceImpl.class);

    @Resource
    private CallCenterCallLogModel callCenterCallLogModel;
    @Resource
    private AudioFileService audioFileService;
    @Resource
    private PaasRedisHelper paasRedisHelper;


    private static String appid = "LTAIolH2W7GWKvMU";
    /**
     * 服务url
     */
    private static String url = "https://nlsapi.aliyun.com/transcriptions";
    private static String accessKeyId = "msNbgeY5hb6vXcTz";
    private static String accessKeySecret = "V5BTbuOZYNWivw4EEM3HdghGAHhaqW";
    private static AliyunRequestBody body = new AliyunRequestBody();
    private static AliyunHttpResponse request = new AliyunHttpResponse();

    @Override
    public void translateLocalPhoneAudio(CallCenterCallLogEntity callCenterCallLogEntity, String filePath) {
        translateLocalAudio(callCenterCallLogEntity, filePath, "nls-service-telephone8khz");
    }

    @Override
    public void translateLocalStandardAudio(CallCenterCallLogEntity callCenterCallLogEntity, String filePath) {
        // 阿里云没有对接普通录音识别功能
        return;
    }

    /**
     * 语音转写本地路径音频
     *
     * @param callCenterCallLogEntity 通话录音持久层对象
     * @param filePath                本地音频路径
     * @param appKey                  app_key	采样率	适用领域
     *                                nls-service-telephone8khz	8KHz	电话销售，客服等
     *                                nls-service-multi-domain	16KHz	短视频，视频直播领域，教育，娱乐，文学，法律，财经等
     *                                nls-service-shurufa16khz	16KHz	语音输入法，社交聊天等
     *                                nls-service-en	16KHz	英语
     *
     * @author 章华隽
     * 创建时间：2018/1/11 上午10:17
     * 修改时间：
     * @version 3.17
     * @since 3.17
     */
    private void translateLocalAudio(CallCenterCallLogEntity callCenterCallLogEntity, String filePath, String appKey) {

        String corpid = callCenterCallLogEntity.getCorpid();
        Long logId = callCenterCallLogEntity.getId();

        String fileOssUrl = audioFileService.upload2AliyunOss(corpid, filePath);
        if (StringUtil.isEmpty(fileOssUrl)) {
            // 上传文件到阿里云OSS失败，将"失败"状态写入Redis缓存
            paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                    corpid + StringConstant.COLON + logId, StringConstant.FAILED, RedisConstant.COMMON_DURATION);
            return;
        }
        // 将"执行中"状态写入Redis缓存
        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                corpid + StringConstant.COLON + logId, StringConstant.WAITING, RedisConstant.COMMON_DURATION);

        //简介页面给出的Appkey
        body.setApp_key(appKey);
        //离线文件识别的文件url,推荐使用oss存储文件。链接大小限制为128MB
        body.setFile_link(fileOssUrl);

        //热词接口
        //使用热词需要指定Vocabulary_id字段，如何设置热词参考文档：[热词设置](~~49179~~)
        // 设置的热词 "销帮帮"、"钉钉"、"CRM"
        body.setVocabulary_id("9f153c9f7b634f2fad2c8d2a6e79304e");

        /* 获取完整识别结果，无需设置本参数！*/
        //body.addValid_time(100,2000,0);       //validtime  可选字段  设置的是语音文件中希望识别的内容,begintime,endtime以及channel
        //body.addValid_time(2000,10000,1);   //validtime  默认不设置。可选字段  设置的是语音文件中希望识别的内容,begintime,endtime以及channel
        /* 获取完整识别结果，无需设置本参数！*/

        // 网络请求成功返回
        int httpSuccessCode = 200;

        /*
         * 发送录音转写请求
         * **/
        String bodyString = JSON.toJSONString(body, true);
        LOG.info("阿里云语音识别（ASR）的请求参数:%s", bodyString);
        AliyunHttpResponse httpResponse = AliyunHttpUtil.sendPost(url, bodyString, accessKeyId, accessKeySecret);
        if (httpResponse.getStatus() == httpSuccessCode) {
            LOG.info("阿里云语音识别（ASR）提交任务成功：%s", httpResponse.getResult());

        } else {
            LOG.error("阿里云语音识别（ASR）提交任务失败：%s", httpResponse.getMessage());

            // 将"失败"状态写入Redis缓存
            paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                    corpid + StringConstant.COLON + logId, StringConstant.FAILED, RedisConstant.COMMON_DURATION);
            return;
        }

        try {
            /*
             * 通过TaskId获取识别结果
             */
            if (httpResponse.getStatus() == httpSuccessCode) {
                String taskId = JSON.parseObject(httpResponse.getResult()).getString("id");
                // 任务执行中的状态
                String runningStatus = "RUNNING";
                // 任务执行成功的状态
                String successStatus = "SUCCEED";
                String status = "RUNNING";
                AliyunHttpResponse getResponse;
                AliyunRsaResponsePojo aliyunRsaResponsePojo = null;
                while (runningStatus.equals(status)) {
                    try {
                        Thread.sleep(15000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        // 恢复中断状态
                        Thread.currentThread().interrupt();
                    }
                    getResponse = AliyunHttpUtil.sendGet(url, taskId, accessKeyId, accessKeySecret);
                    if (getResponse.getStatus() == httpSuccessCode) {
                        LOG.info("aliyun阿里云翻译成功返回的信息：" + JSON.toJSONString(getResponse, SerializerFeature.DisableCircularReferenceDetect));
                        aliyunRsaResponsePojo = JSON.parseObject(getResponse.getResult(), AliyunRsaResponsePojo.class);
                        status = aliyunRsaResponsePojo.getStatus();
                        LOG.info("aliyun解析好的阿里云返回的数据：" + JSON.toJSONString(aliyunRsaResponsePojo, SerializerFeature.DisableCircularReferenceDetect));
                    } else {
                        LOG.error("aliyun阿里云语音识别（ASR）任务执行失败：" + getResponse.getMessage());

                        // 将"失败"状态写入Redis缓存
                        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                                corpid + StringConstant.COLON + logId, StringConstant.FAILED, RedisConstant.COMMON_DURATION);
                        break;
                    }
                }
                if (aliyunRsaResponsePojo != null && successStatus.equals(aliyunRsaResponsePojo.getStatus())) {
                    // 翻译成功
                    LOG.info("aliyun封装数据之前，解析阿里云返回的数据：" + JSON.toJSONString(aliyunRsaResponsePojo.getResult(), SerializerFeature.DisableCircularReferenceDetect));
                    List<RecordContentPojo> recordContents =
                            formatTranslateData2RecordContents(callCenterCallLogEntity.getCallTime()
                                    + callCenterCallLogEntity.getRingTime(), aliyunRsaResponsePojo.getResult());
                    String recordContentsStr = JSON.toJSONString(recordContents, SerializerFeature.DisableCircularReferenceDetect);
                    LOG.info("aliyun根据语音转写转化得到的对话内容：" + recordContentsStr);

                    // 保存翻译成功的结果
                    callCenterCallLogEntity.setTranslatePlatform(StringConstant.PLATFORM_ALIYUN);
                    callCenterCallLogEntity.setTranslateData(JSON.toJSONString(aliyunRsaResponsePojo.getResult(), SerializerFeature.DisableCircularReferenceDetect));
                    callCenterCallLogEntity.setRecordContent(recordContentsStr);
                    callCenterCallLogModel.update(callCenterCallLogEntity);

                    // 将"成功"状态写入Redis缓存
                    paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                            corpid + StringConstant.COLON + logId, StringConstant.SUCCESS, RedisConstant.COMMON_DURATION);
                } else {

                    // 将"失败"状态写入Redis缓存
                    paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                            corpid + StringConstant.COLON + logId, StringConstant.FAILED, RedisConstant.COMMON_DURATION);
                }

            }
        } catch (Exception e) {
            LOG.error("公司（%s）阿里云语音识别（ASR）通话记录（%d）任务执行遇到异常：%s", corpid, logId, e);
            // 将"失败"状态写入Redis缓存
            paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_CALL_LOG_TRANSLATE_STATUS,
                    corpid + StringConstant.COLON + logId, StringConstant.FAILED, RedisConstant.COMMON_DURATION);
        }

    }

    /**
     * 根据翻译结果得到对话内容队列
     *
     * @param startTime             接通电话的时间
     * @param aliyunRsaWordPojo 翻译结果内容
     *
     * @return 对话内容队列
     * @author 章华隽
     * 创建时间：2018/1/11 下午6:58
     * 修改时间：
     * @version 3.17
     * @since 3.17
     */
    private List<RecordContentPojo> formatTranslateData2RecordContents(Integer startTime, List<AliyunRsaWordPojo> aliyunRsaWordPojo) {
        List<RecordContentPojo> recordContents = new ArrayList<>();
        for (AliyunRsaWordPojo it : aliyunRsaWordPojo) {
            int seconds = 0;
            if (it.getBeginTime() != null) {
                seconds = (int) (it.getBeginTime() / 1000L);
            }
            String speaker;
            if (it.getChannelId() == null) {
                speaker = "0";
            } else {
                speaker = it.getChannelId().toString();
            }
            recordContents.add(new RecordContentPojo(speaker, it.getText(), startTime + seconds));
        }
        return recordContents;
    }
}
